#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <memory>
#include <functional>
#include <unistd.h>
#include <pthread.h>
#include "Task.hpp"
#include "Thread.hpp"

namespace Yohifo
{
#define THREAD_NUM 10

    template<class T>
    class ThreadPool
    {
        using func_t = std::function<void(T&)>; // 包装器

    public:
        ThreadPool(func_t func, int num = THREAD_NUM)
            :_num(num), _func(func)
        {
            // 初始化互斥锁和条件变量
            pthread_mutex_init(&_mtx, nullptr);
            pthread_cond_init(&_cond, nullptr);
        }

        ~ThreadPool()
        {
            // 等待线程退出
            for(auto &t : _threads)
                t.join();

            // 互斥锁、条件变量
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_cond);
        }

        void init()
        {
            // 创建一批线程
            for(int i = 0; i < _num; i++)
                _threads.push_back(Thread(i, threadRoutine, this));
        }

        void start()
        {
            // 启动线程
            for(auto &t : _threads)
                t.run();
        }

        // 提供给线程的回调函数（已修改返回类型为 void）
        static void threadRoutine(void *args)
        {
            // 避免等待线程，直接剥离
            pthread_detach(pthread_self());

            auto ptr = static_cast<ThreadPool<T>*>(args);

            while (true)
            {
                // 任务队列是临界资源，需要保护
                ptr->lockQueue();

                // 等待条件满足
                while(ptr->isEmpty())
                    ptr->threadWait();

                T task = ptr->popTask();
                ptr->unlockQueue();

                task();
                ptr->callBack(task); // 回调函数
            }
        }

        // 装载任务
        void pushTask(const T& task)
        {
            // 本质上就是在生产商品，需要加锁保护
            lockQueue();
            _tasks.push(task);

            // 唤醒消费者进行消费
            threadWakeUp();
            unlockQueue();
        }
    
    protected:
        void lockQueue()
        {
            pthread_mutex_lock(&_mtx);
        }

        void unlockQueue()
        {
            pthread_mutex_unlock(&_mtx);
        }

        void threadWait()
        {
            pthread_cond_wait(&_cond, &_mtx);
        }

        void threadWakeUp()
        {
            pthread_cond_signal(&_cond);
        }

        bool isEmpty()
        {
            return _tasks.empty();
        }

        T popTask()
        {
            T task = _tasks.front();
            _tasks.pop();

            return task;
        }

        func_t callBack(T &task)
        {
            _func(task);
        }

    private:
        std::vector<Thread> _threads;
        int _num; // 线程数量
        std::queue<T> _tasks; // 利用 STL 自动扩容的特性，无需担心容量
        pthread_mutex_t _mtx;
        pthread_cond_t _cond;
        func_t _func;
    };
}